#include "stdafx.h"
#include <sys/types.h>
#include <sys/socket.h>
#include "../lib/lib.h"
#include "validate_url.h"
#include <regex.h>
#include "config.h"
#include <sys/select.h>
#include <netinet/in.h>
#include <sys/time.h>
#include "url_type_cache.h"

bool validate_url_from_mysql(MYSQL* mysql, char* domain, uint32_t* timeout,
		uint8_t* tp1, uint8_t* tp2, uint8_t* tp3, uint8_t* rating);
bool validate_url_from_sock(int fd, uint32_t ip, char* domain, int* ptype, int* preason);
bool validate_url_type(uint32_t ip, int type, int* preason);
/*
 * 连接数据库
 */
bool validate_check_mysql(MYSQL* mysql, bool inited)
{
	char		szhost[128]		= {0};
	char		szuser[128]		= {0};
	char		szpwd[128]		= {0};
	char		szdb[128]		= {0};

	if( inited && 0 == mysql_ping(mysql) )
	{
		return true;
	}
	// 新连接数据库
	mysql_init(mysql);

	ini_get_mysql_host(szhost, sizeof(szhost) - 1);
	ini_get_mysql_user(szuser, sizeof(szuser) - 1);
	ini_get_mysql_pwd(szpwd, sizeof(szpwd) - 1);
	ini_get_mysql_database(szdb, sizeof(szdb) - 1);

	if( !mysql_real_connect(mysql, szhost, szuser, szpwd, szdb
					, 0, NULL, CLIENT_FOUND_ROWS) )
	{
		syslog(LOG_ERR, "mysql_real_connet failed: %s"
					, mysql_error(mysql));
		return false;
	}
	return true;
}
/*
 * 初始化
 */
void validate_init(MYSQL* mysql, int* pfd)
{
	char		buf[256]		= {0};

	mysql_init(mysql);
	validate_check_mysql(mysql, false);
	*pfd = socket(AF_INET, SOCK_DGRAM, 0);
}
/*
 * 验证url
 */
bool validate_url(MYSQL* mysql, int fd, uint32_t ip, char* url, int* ptype, int* preason)
{
	char		domain[128]			= {0};
	uint32_t	timeout;
	uint8_t		tp1, tp2, tp3, rating;

	url_get_domain(url, domain);
	// 从缓存获取
	if( utc_query(domain, &timeout, &tp1, &tp2, &tp3, &rating) )
	{
		if(timeout > (int32_t)time(NULL))
		{
			*ptype = tp1;
			return validate_url_type(ip, *ptype, preason);
		}
	}
	// 从数据库获取
	if( validate_url_from_mysql(mysql, domain, &timeout, &tp1, &tp2, &tp3, &rating) )
	{
		*ptype = tp1;
		return validate_url_type(ip, *ptype, preason);
	}
	// 从网络验证
	return validate_url_from_sock(fd, ip, domain, ptype, preason);
}
/*
 * 从MYSQL获取
 */
bool validate_url_from_mysql(MYSQL* mysql, char* domain, uint32_t* timeout,
		uint8_t* tp1, uint8_t* tp2, uint8_t* tp3, uint8_t* rating)
{
	char			sql[1024]			= {0};
	int				res;
	MYSQL_RES*		res_ptr;
	MYSQL_ROW		row;

	snprintf(sql, sizeof(sql)-1, 
			"select unix_timestamp(lasttime),typeid,typeid2,typeid3,rating "
			" from t_urltype where url='%s' and lasttime > now()",
			domain);
	if( false == validate_check_mysql(mysql, true) )
	{
		return false;
	}
	res = mysql_query(mysql, sql);
	if( res )
	{
		syslog(LOG_ERR, "mysql_query %s: %s", sql, mysql_error(mysql));
		return false;
	}
	// 获取返回值
	res_ptr = mysql_store_result(mysql);
	if(NULL == res_ptr)
	{
		return false;
	}
	// 返回真
	row = mysql_fetch_row(res_ptr);
	if( !row )
	{
		mysql_free_result(res_ptr);
		return false;
	}
	*timeout = atoi(row[0]);
	*tp1 = atoi(row[1]);
	*tp2 = atoi(row[2]);
	*tp3 = atoi(row[3]);
	*rating = atoi(row[4]);
	mysql_free_result(res_ptr);
	
	utc_set(domain, *timeout, *tp1, *tp2, *tp3, *rating);
	return true;
}
/*
 * 清理
 */
void validate_clean(MYSQL* mysql, int fd)
{
	mysql_close(mysql);
	close(fd);
}
/*
 * 从远程验证URL
 */
bool validate_url_from_sock(int fd, uint32_t ip, char* domain, int* ptype, int* preason)
{
	char					data[1024]		= {0};
	qut_pack_t*				ppack			= (qut_pack_t*)data;
	struct sockaddr_in		addr			= {0};
	int						len;

	len = 8 + 1 + strlen(domain);
	ppack->version = 2;
	ppack->service = 0;
	strcpy(ppack->url, domain);
	ppack->url_size = strlen(domain);

	des_encrypt((char *)ini_get_des_key(), &data[4], len, &len);
	ppack->des_size = htons(len);

	addr.sin_family = AF_INET;
	addr.sin_port = htons(2053);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	sendto(fd, data, 4 + len, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
	// 接收数
	fd_set		set;
	struct timeval		tout;
	
	FD_ZERO(&set);
	FD_SET(fd, &set);
	tout.tv_sec = 7;
	tout.tv_usec = 0;
	*ptype = -1;

	if(-1 != select(1, &set, NULL, NULL, &tout))
	{
		if(FD_ISSET(fd, &set))
		{
			memset(data, 0, sizeof(data));
			len = sizeof(struct sockaddr_in);
			recvfrom(fd, data, sizeof(data), 0, (struct sockaddr*)&addr, &len);
			des_decrypt((char *)ini_get_des_key(), &data[4], ntohs(ppack->des_size), &len);
			data[4 + len] = 0;
			if(strcmp(ppack->url, domain) == 0)
			{
				*ptype = ppack->head.res.url_tp1;
				utc_set(domain, ppack->head.res.time,
						ppack->head.res.url_tp1,
						ppack->head.res.url_tp2,
						ppack->head.res.url_tp3,
						ppack->head.res.rating);
			}
		}
	}
	
	return validate_url_type(ip, *ptype, preason);
}

bool validate_url_type(uint32_t ip, int type, int* preason)
{
	*preason = ini_get_type_reason(type);
	return 0 == *preason;
}
